package model;

import java.io.IOException;
import java.util.Formatter;

import manager.IDictionary;
import manager.IToken;

/**
 * Clase que provee el armado del token y todo el comportamiento para tratar un token.
 * Encargada de ir agregando los token que son palabras reservadas al diccionario.
 * 
 *
 */

public class Token implements IToken {

	private StringBuilder text = new StringBuilder();
	private int type;
	private boolean retornable = true;
	private int[] coords;
	
	public Token(int type) {
		this.type = type;
		
		switch (type) {
			//TOKEN_IDENTIFICADOR	=  0; // a-z/A-Z 0-9
			//TOKEN_PALABRA_RESERVADA= 1; // si, entonces, sino, etc.
			//TOKEN_NUM_ENTERO		=  2; // 1234
			//TOKEN_NUM_NATURAL		=  3; // 1234n
			//TOKEN_CADENA			=  4; // 'mi cadena'
			case 4: this.append("'");break;
			//TOKEN_COMENTARIO		=  5; // {soy un comentario}
			case 5: 
				this.append("{");
				this.setRetornable(false);
				break;
			//TOKEN_DOS_PUNTOS		=  6; // :
			case 6: this.append(":");break;
			//TOKEN_ASIGNACION		=  7; // :=
			case 7: this.append(":=");break;
			//TOKEN_OPER_IGUAL		=  8; // =
			case 8: this.append("=");break;
			//TOKEN_OPER_MAS_INT	=  9; // + (para entero)
			case 9: this.append("+");break;
			//TOKEN_OPER_MAS_NAT	= 10; // ++ (para natural)
			case 10: this.append("++");break;
			//TOKEN_OPER_MENOS_INT	= 11; // - (para entero)
			case 11: this.append("-");break;
			//TOKEN_OPER_MENOS_NAT	= 12; // -- (para natural)
			case 12: this.append("--");break;
			//TOKEN_OPER_MULT_INT	= 13; // * (para entero)
			case 13: this.append("*");break;
			//TOKEN_OPER_MULT_NAT	= 14; // ** (para natural)
			case 14: this.append("**");break;
			//TOKEN_OPER_DIV_INT	= 15; // / (para entero)
			case 15: this.append("/");break;
			//TOKEN_OPER_DIV_NAT	= 16; // // (para natural)
			case 16: this.append("//");break;
			//TOKEN_OPER_MENOR		= 17; // <
			case 17: this.append("<");break;
			//TOKEN_OPER_MAYOR		= 18; // >
			case 18: this.append(">");break;
			//TOKEN_OPER_MENOR_IGUAL= 19; // <=
			case 19: this.append("<=");break;
			//TOKEN_OPER_MAYOR_IGUAL= 20; // >=
			case 20: this.append(">=");break;
			//TOKEN_OPER_DISTINTO	= 21; // >=
			case 21: this.append("<>");break;
			//TOKEN_PARENTESIS_IZQ	= 22; // (
			case 22: this.append("(");break;
			//TOKEN_PARENTESIS_DER	= 23; // )
			case 23: this.append(")");break;
			//TOKEN_CORCHETE_IZQ	= 24; // [
			case 24: this.append("[");break;
			//TOKEN_CORCHETE_DER	= 25; // ]
			case 25: this.append("]");break;
			//TOKEN_COMA			= 26; // ,
			case 26: this.append(",");break;
			//TOKEN_PUNTO_COMA		= 27; // ;
			case 27: this.append(";");break;
			//TOKEN_SEPARADOR		= 28; // ' ' \n \t \r \f \b
			case 28: this.setRetornable(false);break;
			//TOKEN_ERROR			= 29; // caracteres invalidos
			//TOKEN_FIN_DE_ARCHIVO	= 30; // EOF
			case 30: this.append("EOF");break;
		}
	}
	
	public Token(String palabraReservada) {
		IDictionary dic = Dictionary.getInstance();
		
		if (dic.isValid(palabraReservada)) {
			this.type = IToken.TYPE_PALABRA_RESERVADA;
			this.append(palabraReservada);
		} else {
			throw new IllegalArgumentException("La palabra no se encuentra definida como palabra reservada.");
		}
	}

	@Override
	public String getTokenText() {
		return this.text.toString();
	}

	@Override
	public int getTokenType() {
		return type;
	}
	
	@Override
	public void setTokenType(int type) {
		this.type = type;
	}
	
	@Override
	public IToken append(String s) throws IllegalStateException {
		this.text.append(s);
		return this;
	}

	@Override
	public boolean isRetornableTOAs() {
		return retornable;
	}

	@Override
	public void setRetornable(boolean retornable) {
		this.retornable = retornable;
	}

	@Override
	public int[] getCoords() {
		return this.coords;
	}

	@Override
	public void setCoords(int[] coords) {
		this.coords = coords;
	}
	
	@Override
	public boolean equals(Object obj) { 
		
		// Validaciones genericas
		if (this == obj) {return true;}
		if (obj == null) {return false;}
		if (!(obj instanceof Token)) {return false;}
		
		// Validaciones
		Token other = (Token) obj;
		if (type != other.type){return false;}
		if (retornable != other.retornable) {return false;}
		if (text == null && other.text != null) {return false;}
		if (type != IToken.TYPE_IDENTIFICADOR &&  //Al identificador no lo podemos validar por su lexema
			type != IToken.TYPE_NUM_NATURAL &&  //Al Numero Natural no lo podemos validar por su lexema
			type != IToken.TYPE_NUM_ENTERO &&  //Al Numero Entero no lo podemos validar por su lexema
			type != IToken.TYPE_CADENA &&  //Al Numero Entero no lo podemos validar por su lexema
			!text.toString().equals(other.text.toString())){return false;} //text es un stringbuilder
		
		return true;
	}


	public String toString() {
		
		StringBuffer sb = new StringBuffer();
		IDictionary dic = Dictionary.getInstance();
		
		sb.append("Lexema (type:").append(this.getTokenType()).append(" ").
		   append(dic.getTokenDescription(this.getTokenType())).
		   append(")[").append(this.getCoords()[0]).append(",").append(this.getCoords()[1]).append("]: ");
		
		Formatter f = new Formatter();
		f.format("%.50s",sb.toString());
		
		try {
			return f.out().append(this.getTokenText()).toString();
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
	}

}
